i. 特殊命令 ID :
1. + : 0x2B ,用于向连接对方声明启用某项功能;
2. - : 0x2D ,用于向连接对方声明禁用某项功能;
3. 以上两个命令 ID 是固定的。在实现上,一个连接通过向对方发送: +II 表示支持扩展协议,发送: -II 表示禁用扩展协议;
4. 任何一方在未声明支持扩展协议前如果发送除 +II 或 -II 外的数据包,对方有权关闭连接( BS 的实现是忽略而不是关闭);
5. 通常情况下, +II 或 -II 的命令在握手结束,发送完 BitField 后;
6. 如果对方未声明支持 BS 扩展协议,则本地应默认对方是禁用的;
7. +II 和 -II 的数据包结构:
声明支持BSⅡ扩展协议(下表)
数据长度 |
数据含义 |
数据内容 |
备注 |
4 |
数据量 |
0x0D |
|
1 |
命令ID |
0x07 |
|
4 |
伪区块索引 |
0x00000000 |
固定为0 |
4 |
伪区块起始点 |
0x00000002 |
固定为2 |
1 |
扩展命令ID |
0x2B |
ASCII:+ |
3 |
协议数据 |
\x49\x49\x00 |
ASCII;II\0 |
声明禁用BSⅡ扩展协议(下表)
数据长度 |
数据含义 |
数据内容 |
备注 |
4 |
数据量 |
0x0D |
|
1 |
命令ID |
0x07 |
|
4 |
伪区块索引 |
0x00000000 |
固定为0 |
4 |
伪区块起始点 |
0x00000002 |
固定为2 |
1 |
扩展命令ID |
0x2D |
ASCII:- |
3 |
协议数据 |
\x49\x49\x00 |
ASCII:II\0 |
1. 理论上,除了0x2B和0x2D以外所有介于0-255之间的数都可以用作命令ID,各命令ID所含协议数据格式由开发者自行定义;
2. 推荐支持的命令ID:
A. ‘+':0x2B,用'+'或'-‘命令声明自己是否支持GZIP压缩;声明支持GZIP数据压缩(下表)
数据长度 |
数据含义 |
数据内容 |
备注 |
4 |
数据量 |
0x0F |
|
1 |
命令ID |
0x07 |
|
4 |
伪区块索引 |
0x00000000 |
固定为0 |
4 |
伪区块起始点 |
0x00000002 |
固定为2 |
1 |
扩展命令ID |
0x2B |
ASCII:+ |
5 |
协议数据 |
\x47\x5A\x49\x50\x00 |
ASCII:GZIP\0 |
B ‘*':0x2A,压缩过的区块数据,BSII支持在发送数据块前先进行GZIP压缩,以便提高网络传输效率;
数据压缩包格式(下表)
数据长度 |
数据含义 |
数据内容 |
备注 |
4 |
数据量 |
? |
从命令ID开始算 |
1 |
命令ID |
0x07 |
|
4 |
伪区块索引 |
0x00000000 |
固定为0 |
4 |
伪区块起始点 |
0x00000002 |
固定为2 |
1 |
扩展命令ID |
0x2A |
ASCII:* |
4 |
区块索引 |
? |
与BT协议类似 |
4 |
区块起始点 |
? |
与BT协议类似 |
4 |
压缩前数据量 |
? |
不含协议头 |
C ‘@' : 0x40 ,反向提供本机地址。通常情况下,对于一个连入的连接,本地是不知道连接对方监听的 TCP 端口的,如果因为网络故障导致连接被断开的话,本地将不可能再主动与对方建立连接,通过 '@' 命令,连接发起方可以告知对方本地的监听端口( IP 地址请直接取 TCP 连接的对方 IP )。
(下表)本地反向提供地址
数据长度 |
数据含义 |
数据内容 |
备注 |
4 |
数据量 |
0x10 |
从命令ID开始算 |
1 |
命令ID |
0x07 |
|
4 |
伪区块索引 |
0x00000000 |
固定为0 |
4 |
伪区块起始点 |
0x00000002 |
固定为2 |
1 |
扩展命令ID |
0x40 |
ASCII:@ |
4 |
保留 |
0 |
保留,请设为0 |
2 |
本地监听端口 |
? |
本地TCP监听端口 |
D '%' : 0x25 ,向连接对方请求共享连接信息。在默认 BT 协议里,连接的种子信息只能从 Tracker 服务器获取,而在具体实现上,其实服务器是有不确定性的,很多下载者在很多时候并不一定总能从服务器获取种子信息,这就导致了会有很大的时间上的浪费。 BSII 通过添加“连接共享”这个基于 BS 扩展协议的实现很好的解决了这个问题。连接一方通过向支持扩展协议的对方发送 '%' 命令请求对方共享连接信息。(下表)
向连接对方请求共享连接信息
数据长度 |
数据含义 |
数据内容 |
备注 |
4 |
数据量 |
0x0E |
从命令ID开始算 |
1 |
命令ID |
0x07 |
|
4 |
伪区块索引 |
0x00000000 |
固定为0 |
4 |
伪区块起始点 |
0x00000002 |
固定为2 |
1 |
扩展命令ID |
0x25 |
ASCII:% |
4 |
期望连接数 |
0 |
1到1024,参见下表 |
E ‘&' : 0x26 ,发送连接信息,连接一方在收到对方的 '%' 命令后,向对方发送共享的连接信息。注意不要向对方发送超过对方期望连接数的连接数量( BSII 默认是 256 个连接)。(下表)向连接对方发送连接信息
数据长度 |
数据含义 |
数据内容 |
备注 |
4 |
数据量 |
? |
从命令ID开始算 |
1 |
命令ID |
0x07 |
|
4 |
伪区块索引 |
0x00000000 |
固定为0 |
4 |
伪区块起始点 |
0x00000002 |
固定为2 |
1 |
扩展命令ID |
0x26 |
ASCII:& |
1 |
数据开始标志 |
1或0 |
参考:数据标志 |
1 |
数据结束标志 |
1或0 |
参考:数据标志 |
? |
连接信息 |
? |
经过GZIP压缩 |
上表中的连接信息是由很多个连接单元 (unit) 组成的,每一个 unit 结构定义如下:
const int PeerSeedSize = 64;
struct tagPeerSeed
{
char None[25]; //25Bytes,not used yet, please set all bytes to 0
int Port; //4Bytes,sorry~~, get it in this way: (ntohl(Port)&0xFFFF)
ulong Address; //4Bytes, in network byte order
char ID[20]; //20Bytes. Peer Id
char Reserved[PeerSeedSize-25-4-4-20]; //set all bytes to 0
}; |
从目前来看,这个结构有点庸肿,但是由于目前 None 和 Reserved 字段都是 0 ,所以用 GZIP 压缩可以达到很高的压缩比,同时也为将来扩展留下了很好的后路。
注: BSII 支持接收未经过 GZIP 压缩的连接信息,但所有 BSII 发送的连接信息都是经过 GZIP 压缩的,这样只占用很少的网络流量。
F 目前 BSII 已经使用的其它命令 ID : '?', ‘=', ‘#', ‘$', ‘(‘, ‘)' ;
G 各个软件作者可以自由使用 0x80-0xFF 的命令 ID ,只要你能确保那是自己定义的数据包 J ,但对于 0x00-0x7F 的命令 ID ,请尽可能的先跟其他软件作者联系 ( 比如 BS) 。
附注 1 :关于数据压缩 BS 采用基于 zlib 的 GZIP 压缩技术,当把内存数据块进行压缩时,压缩后的数据块包含标准的 GZIP 数据头,但不包含 GZIP 文件的结束标志 (zlib 只提供了基于文件的 GZIP 实现,没有提供基于内存的 GZIP 压缩实现, BS 的作者根据 zlib 自行实现了一个模块用于对内存块进行压缩,如果你需要这方面的资料可以跟 BS 的作者联系 ) 。
附注 2 :关于在 '%' 命令里提到的数据标志:因为 BT 协议定义了数据包最大不能超过 128KB ,所以 BS 的扩展协议的数据包一般不超过 64KB ,这样在传送大数据块时力有不足,所以 BS 通过数据标志来组合大块数据,在表 10 中有一个数据开始标志和数据结束标志,以下是其含义:
1 数据开始标志: 1 表示这块数据是一大块数据的开始, 0 则表示本块数据是前一块未完数据的继续;
2 数据结束标志: 1 表示这块数据是一大块数据的结束, 0 则表示本块数据是前一块未完数据的继续;
3 如果前一个数据块未包含结束标志,而本数据块包含了开始标志,则表示以前的数据已经作废,对方必须重新表示当前数据;
4 如果所有数据可以通过一个数据块发完,那么可以将开始和结束标志都置为 1 ;